package com.time.workbench.efficient.handle;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.google.gson.JsonObject;
import com.jcraft.jsch.Session;
import com.time.workbench.core.exception.DeployException;
import com.time.workbench.core.util.AssertUtil;
import com.time.workbench.efficient.consts.CmdConst;
import com.time.workbench.efficient.entity.dto.ServerSessionConnect;
import com.time.workbench.efficient.entity.dto.ServerSessionInfo;
import com.time.workbench.efficient.util.DeployUtil;
import com.time.workbench.efficient.util.JschExecuteUtil;
import com.time.workbench.efficient.util.JschUtil;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import org.codehaus.jettison.json.JSONObject;

import java.io.File;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;


/**
 * tomcat部署
 */
@EqualsAndHashCode(callSuper = true)
@Data
@Slf4j
public class TomcatDeploy extends AbstractDeploy {


    /**
     * git拉取的本地目录
     */
    private String gitPullBaseDirectory;

    /**
     * git地址
     */
    private String gitRemoteAddress;

    /**
     * 拉取分支
     */
    private String branch;

    /**
     * 编译模块
     */
    private String packageModule = "";

    /**
     * 项目code
     */
    private String projectCode;


    /**
     * tomcatHttp端口 未指定随机
     */
    private Integer httpPort;

    /**
     * 检查次数
     */
    private final Integer monitorNumber = 30;
    /**
     * 每次间隔时长
     */
    private final Integer monitorTime = 1000;

    /**
     * 程序运行pid (内部维护)
     */
    @Setter(AccessLevel.NONE)
    private String pid;

    /**
     * git源码路径 (内部维护)
     */
    @Setter(AccessLevel.NONE)
    private String gitSourceDirect;


    private final static String tomcatWebapp = "webapps";
    private final static String tomcatConfig = "conf";
    private final static String tomcatBin = "bin";


    @Override
    @SneakyThrows
    public void init() {
        super.init();
        for (ServerSessionConnect serverSessionConnect : serverSessionConnects) {
            Session serverSession = DeployUtil.getSession(serverSessionConnect.getIp(), serverSessionConnect.getPort(), serverSessionConnect.getUserName(), serverSessionConnect.getPassword());
            ServerSessionInfo serverSessionInfo = new ServerSessionInfo();
            serverSessionInfo.setServerSession(serverSession);
            serverSessionInfo.setProjectPath(serverSessionConnect.getDeployPath() + File.separator + projectCode + File.separator);
            serverSessionInfo.setServerSessionConnect(serverSessionConnect);
            serverSessions.add(serverSessionInfo);
        }


        String tomcatFileName = "apache-tomcat-8.5.69";
        String tempFilePath = File.separator + "opt" + File.separator;
        String tomcatPosition = tempFilePath + tomcatFileName + ".tar.gz";
        File tomcatLocalFile = new File(tomcatPosition);

        // 本地目录不存在初始化tomcat
        if (!FileUtil.exist(tomcatLocalFile)) {
            InputStream tomcatZipStream = ResourceUtil.getStream("deploy/apache-tomcat-8.5.69.tar.gz");
            FileUtil.mkdir(tempFilePath);
            tomcatLocalFile.createNewFile();
            FileUtil.writeFromStream(tomcatZipStream, tomcatLocalFile);
        }

        //远程目录不存在初始化
        for (ServerSessionInfo serverSession : serverSessions) {
            String findTomcatExec = JschUtil.exec(serverSession.getServerSession(), StrUtil.format(CmdConst.find, tomcatPosition), StandardCharsets.UTF_8);
            if (StrUtil.isEmpty(findTomcatExec)) {
                JschExecuteUtil.scpTo(tomcatLocalFile.getAbsolutePath(), serverSession.getServerSession(), tomcatPosition);
            }

            // 项目目录不存在初始化
            String findProjectExec = JschUtil.exec(serverSession.getServerSession(), StrUtil.format(CmdConst.findMax1D, serverSession.getProjectPath(), tomcatFileName), StandardCharsets.UTF_8);
            // 判断下面有没有tomcat
            String findProjectTomcatExec = JschUtil.exec(serverSession.getServerSession(), StrUtil.format(CmdConst.findMax1D, serverSession.getProjectPath(), tomcatBin), StandardCharsets.UTF_8);

            if (StrUtil.isEmpty(findProjectExec) && StrUtil.isEmpty(findProjectTomcatExec)) {
                // 创建项目文件
                JschUtil.exec(serverSession.getServerSession(), StrUtil.format(CmdConst.mkdirP, serverSession.getProjectPath()), StandardCharsets.UTF_8);

                // tomcat解压
                JschUtil.exec(serverSession.getServerSession(), StrUtil.format(CmdConst.tarUnTarGz, tomcatPosition, serverSession.getProjectPath()), StandardCharsets.UTF_8);

                // 生成端口
                Integer serverPort = DeployUtil.newPort(serverSession.getServerSession());
                Integer redirectPort = DeployUtil.newPort(serverSession.getServerSession());
                if (ObjectUtil.isEmpty(httpPort)) {
                    httpPort = DeployUtil.newPort(serverSession.getServerSession());
                }

                // 修改xml端口
                String str = ResourceUtil.readUtf8Str("deploy/server.xml");
                JschExecuteUtil.remoteEdit(serverSession.getServerSession(), serverSession.getProjectPath() + tomcatFileName + File.separator + tomcatConfig + File.separator + "server.xml", (listStr) -> {
                    String[] split = StrUtil.format(str, serverPort, httpPort, redirectPort).split("\n");
                    return CollectionUtil.newArrayList(split);
                });

                // 修改tomcat  catalina.sh权限
                JschUtil.exec(serverSession.getServerSession(), StrUtil.format(CmdConst.chmod777, serverSession.getProjectPath() + tomcatFileName + File.separator + tomcatBin + File.separator + "catalina.sh"), StandardCharsets.UTF_8);
            }

            if (StrUtil.isNotEmpty(findProjectExec)) {
                serverSession.setProjectPath(serverSession.getProjectPath() + tomcatFileName + File.separator);
            }
        }


        // 移动目录
        gitSourceDirect = gitPullBaseDirectory + File.separator + projectCode;
        if (packageModule == null) {
            packageModule = "";
        }

        // 如果是集中服务器
        if (buildConfig.getMode().equals("gather")) {
            buildServerSession = DeployUtil.getSession(buildConfig.getServerIp(), buildConfig.getPort(), buildConfig.getUsername(), buildConfig.getPassword());
            if (!buildServerSession.isConnected()) {
                buildServerSession.connect();
            }
        }
    }

    @Override
    public void connectServer() {
        super.connectServer();
        for (ServerSessionInfo serverSession : serverSessions) {
            DeployUtil.connectServer(serverSession.getServerSession());
            if (buildServerSession != null)
                DeployUtil.connectServer(buildServerSession);
        }
    }


    @Override
    public void pullCode() {
        super.pullCode();
        pullExtracted(serverSessions, buildServerSession, this.gitPullBaseDirectory, this.gitSourceDirect, buildConfig, this.projectCode, this.gitRemoteAddress, this.branch);
    }

    @Override
    public boolean packageCode() {
        super.packageCode();
        if (packageModule == null) {
            packageModule = "";
        }
        packageExtracted(serverSessions, buildServerSession, gitSourceDirect, projectCode, packageModule, "war");

        return isExistPackName();
    }


    @Override
    public void stop(ServerSessionInfo serverSessionInfo) {
        super.stop(serverSessionInfo);
        packageFileName = DeployUtil.getPackageFile(gitSourceDirect, packageModule, serverSessionInfo.getServerSession(), "war");
        if (StrUtil.isEmpty(packageFileName)) {
            log.info("没找到war包");
            throw new DeployException("没找到备份的war包");
        }
        JschUtil.exec(serverSessionInfo.getServerSession(), StrUtil.format(CmdConst.tomcatStop, projectPath), StandardCharsets.UTF_8);
    }

    @Override
    public void backupPackage(ServerSessionInfo serverSessionInfo) {
        super.backupPackage(serverSessionInfo);
        String source = projectPath + tomcatWebapp + File.separator + "ROOT.war";
        String target = projectPath + tomcatWebapp + File.separator + "ROOT.war.bak";
        // 备份包
        JschUtil.exec(serverSessionInfo.getServerSession(), StrUtil.format(CmdConst.mvF, source, target), StandardCharsets.UTF_8);

    }

    @Override
    public void movePackage(ServerSessionInfo serverSessionInfo) {
        super.movePackage(serverSessionInfo);
        String source = gitPullBaseDirectory + File.separator + projectCode + File.separator + packageModule + File.separator + "target" + File.separator + packageFileName;
        String target = projectPath + tomcatWebapp + File.separator;
        JschUtil.exec(serverSessionInfo.getServerSession(), StrUtil.format(CmdConst.mvF, source, target), StandardCharsets.UTF_8);
    }

    @Override
    public void start(ServerSessionInfo serverSessionInfo) {
        super.start(serverSessionInfo);
        // 启动
        JschUtil.exec(serverSessionInfo.getServerSession(), StrUtil.format(CmdConst.tomcatStart, projectPath), StandardCharsets.UTF_8);
        //获取pid
        pid = JschUtil.exec(serverSessionInfo.getServerSession(), StrUtil.format(CmdConst.tomcatPid, projectPath), StandardCharsets.UTF_8);
        if (StrUtil.isEmpty(this.pid) || "0".equals(this.pid))
            throw new RuntimeException("未找到pid");
        pid = pid.replace("\n", "");
    }


    @Override
    public boolean monitorStatus(ServerSessionInfo serverSessionInfo) {
        super.monitorStatus(serverSessionInfo);
        return DeployUtil.monitorPid(pid, monitorNumber, monitorTime, projectCode, serverSessionInfo.getServerSession());
    }

    @Override
    public void freed(ServerSessionInfo serverSessionInfo) {
        super.freed(serverSessionInfo);
        if (serverSessionInfo != null)
            JschUtil.close(serverSessionInfo.getServerSession());
        if (buildServerSession != null)
            JschUtil.close(buildServerSession);
    }

    @Override
    public void notice() {
        super.notice();
    }
}
